﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Histograms;

namespace LowLevelGraphics.Filter
{
    //TODO: add other countings, i.e. almost all from PROCESSING_MODE
    /// <summary>
    /// If m_bColorValues is true, we will create a
    /// histogram and just use
    /// Color.FromArgb(ColorCountInHistogrammOfColor(Color))
    /// otherwise we will normalize this to gray.
    /// 
    /// This maps each color to its appearance count
    /// 
    /// This results in most cases in clean structures like any geometrical shapes
    /// if there are gradients in the image
    /// </summary>
    public class ColorCount : BaseImageFilter
    {
        protected bool m_bColorValues = false;
        
        protected float m_fFactor = 256.0f;
        //TODO: check if this can be deleted (inheritance)
        protected float m_fOffset = 16.0f;

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorCount"/> class.
        /// </summary>
        public ColorCount()
            : this(false, 1.0f, 0.0f)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorCount"/> class.
        /// </summary>
        /// <param name="_bColorValues">if set to <c>true</c> [_b color values].</param>
        /// <param name="_fFactor">The _f factor.</param>
        /// <param name="_fOffset">The _f offset.</param>
        public ColorCount(bool _bColorValues, float _fFactor, float _fOffset)
        {
            m_bColorValues = _bColorValues;
            m_fFactor = _fFactor;
            m_fOffset = _fOffset;
            M_PROCESSING_MODE = PROCESSING_MODE.SumARGB;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_colorCount"></param>
        internal ColorCount(ColorCount _colorCount)
        {
            this.m_bColorValues = _colorCount.m_bColorValues;
            this.m_fFactor = _colorCount.m_fFactor;
            this.m_fOffset = _colorCount.m_fOffset;
            this.M_PROCESSING_MODE = _colorCount.M_PROCESSING_MODE;
        }

        /// <summary>
        /// Gets or sets the PROCESSINGMODE.
        /// </summary>
        /// <value>The PROCESSINGMODE.</value>
        public PROCESSING_MODE PROCESSINGMODE
        {
            get { return M_PROCESSING_MODE; }
            set { M_PROCESSING_MODE = value; }
        }

        /// <summary>
        /// Gets or sets the factor.
        /// </summary>
        /// <value>The factor.</value>
        public float Factor
        {
            get { return m_fFactor; }
            set { m_fFactor = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [color values].
        /// </summary>
        /// <value><c>true</c> if [color values]; otherwise, <c>false</c>.</value>
        public bool ColorValues
        {
            get { return m_bColorValues; }
            set { m_bColorValues = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;

            ColorCounter colorCounter = new ColorCounter(bitmap, M_PROCESSING_MODE);
            colorCounter.Process();

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;
            
            Color color = Color.Transparent;

            float dGrayValue = -1.0f;
            int nGrayValue = -1;
            int nColorCount = -1;
            int nMaxCount = colorCounter.MaxCount;

            int y = 0;
            int x = 0;

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = bitmap.GetPixel(x, y);
                    nColorCount = colorCounter.GetValue(color);
                    if (m_bColorValues)
                    {
                        color = Color.FromArgb((int)(nColorCount * m_fFactor + m_fOffset));
                    }
                    else
                    {
                        dGrayValue = (float)nColorCount / (float)nMaxCount;
                        dGrayValue = dGrayValue * m_fFactor + m_fOffset;
                        nGrayValue = (int)(dGrayValue * 255.0f);
                        color = Color.FromArgb(nGrayValue, nGrayValue, nGrayValue);
                    }
                    bitmap.SetPixel(x, y, color);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ColorCount(this);
        }
    }
}
